package onfido

import (
	"code.bydev.io/cht/customer/kyc_admin_service/internal/constant"
	"encoding/json"

	"code.bydev.io/cht/customer/kyc-stub.git/pkg/bybit/kyc/common/enums"
	byoneconfig "code.bydev.io/cht/customer/kyc_admin_service/internal/config"
	"code.bydev.io/cht/customer/kyc_admin_service/internal/pkg/kycprovider/dto"
	"emperror.dev/errors"
)

type APIError struct {
	Error struct {
		Type    string      `json:"type"`
		Message string      `json:"message"`
		Fields  interface{} `json:"fields"`
	} `json:"error"`
}

type OnfidoIDNumber struct {
	Type      string `json:"type"`
	Value     string `json:"value"`
	StateCode string `json:"state_code"`
}

type OnfidoAddress struct {
	FlatNumber     string `json:"flat_number"`
	BuildingNumber string `json:"building_number"`
	BuildingName   string `json:"building_name"`
	Street         string `json:"street"`
	SubStreet      string `json:"sub_street"`
	Town           string `json:"town"`
	State          string `json:"state"`
	Postcode       string `json:"postcode"`
	Country        string `json:"country"`
	Line1          string `json:"line1"`
	Line2          string `json:"line2"`
	Line3          string `json:"line3"`
}

type OnfidoLocation struct {
	IPAddress          string `json:"ip_address"`
	CountryOfResidence string `json:"country_of_residence"`
}

type OnfidoApplicant struct {
	ID          string           `json:"id"`
	CreatedAt   string           `json:"created_at"`
	Sandbox     bool             `json:"sandbox"`
	FirstName   string           `json:"first_name"`
	LastName    string           `json:"last_name"`
	Email       string           `json:"email"`
	Dob         string           `json:"dob"`
	DeleteAt    string           `json:"delete_at"`
	Href        string           `json:"href"`
	Address     OnfidoAddress    `json:"address"`
	IDNumbers   []OnfidoIDNumber `json:"id_numbers"`
	PhoneNumber string           `json:"phone_number"`
	Location    OnfidoLocation   `json:"location"`
}

// OnfidoWorkflowRun Onfido workflow run object
// https://documentation.onfido.com/#workflow-run-object
type OnfidoWorkflowRun struct {
	ID                string                 `json:"id"`
	ApplicantID       string                 `json:"applicant_id"`
	WorkflowID        string                 `json:"workflow_id"`
	WorkflowVersionID int                    `json:"workflow_version_id"`
	Status            WorkflowStatus         `json:"status"`
	DashboardURL      string                 `json:"dashboard_url"`
	Output            interface{}            `json:"output"`
	Reasons           []string               `json:"reasons"`
	Error             OnfidoWorkflowRunError `json:"error"`
	CreatedAt         string                 `json:"created_at"`
	UpdatedAt         string                 `json:"updated_at"`
	Link              OnfidoWorkflowRunLink  `json:"link"`
	Level             dto.KYCLevel
	ExternalUserID    string
}

func (r *OnfidoWorkflowRun) GetWorkflowRunID() string {
	return r.ID
}

func (r *OnfidoWorkflowRun) GetApplicantID() string {
	return r.ApplicantID
}

func (r *OnfidoWorkflowRun) GetExternalUserID() string {
	return r.ExternalUserID
}

func (r *OnfidoWorkflowRun) GetLevel() dto.KYCLevel {
	return r.Level
}

func (r *OnfidoWorkflowRun) GetLevelName() string {
	return r.Level.String()
}

func (r *OnfidoWorkflowRun) IsLevel1() bool {
	return r.Level == dto.Level1
}

func (r *OnfidoWorkflowRun) SetKYCLevel(conf *byoneconfig.OnfidoConfig) dto.KYCLevel {
	switch r.WorkflowID {
	case conf.Level1WorkflowIDTwoSide, conf.Level1WorkflowIDOneSide, conf.Level1WorkflowIDWeb:
		return dto.Level1
	case conf.Level2WorkflowID:
		return dto.Level2
	case conf.SecondaryLevel1WorkflowID:
		return dto.Level1Secondary
	case conf.SecondaryLevel2WorkflowID:
		return dto.Level2Secondary
	case conf.Level2DecoupleWorkflowID:
		return dto.KYCLevel2POA
	case conf.SupplementLevel2DecoupleWorkflowID:
		return dto.KYCLevel2POASupplement
	}
	return dto.LevelDefault
}

func (r *OnfidoWorkflowRun) GetReviewResult() dto.ReviewResult {
	switch r.Status {
	case WorkflowStatusApproved:
		return dto.ReviewResultPass
	case WorkflowStatusDeclined, WorkflowStatusError, WorkflowStatusReview:
		return dto.ReviewResultReject
	}
	return dto.ReviewResultUnknown
}

func (r *OnfidoWorkflowRun) GetState() dto.ReviewState {
	return r.Status.ToReviewState()
}

type DocID struct {
	ID string `json:"id"`
}

type Document struct {
	Type  string `json:"type"`
	Value string `json:"value"`
}

// Level1WorkflowRunOutput Identity Verification(Level1) workflow run output
type Level1WorkflowRunOutput struct {
	Address         string             `json:"address"`
	DocumentType    OnfidoDocumentType `json:"document_type"`
	DateOfBirth     string             `json:"date_of_birth"`
	DateOfExpiry    string             `json:"date_of_expiry"`
	DocumentIds     []DocID            `json:"document_ids"`
	DocumentNumber  string             `json:"document_number"`
	DocumentNumbers []Document         `json:"document_numbers"`
	FirstName       string             `json:"first_name"`
	Gender          string             `json:"gender"`
	IssuingCountry  string             `json:"issuing_country"`
	IssuingDate     string             `json:"issuing_date"`
	LastName        string             `json:"last_name"`
	LivePhotoIds    []DocID            `json:"live_photo_ids"`
	MrzLine1        string             `json:"mrz_line1"`
	MrzLine2        string             `json:"mrz_line2"`
	Nationality     string             `json:"nationality"`
	PersonalNumber  string             `json:"personal_number"`
	PlaceOfBirth    string             `json:"place_of_birth"`
	FaceDetected    string             `json:"face_detected"`
	FaceMatch       string             `json:"face_match"`
}

func (l1o *Level1WorkflowRunOutput) GetDocIDs() []DocID {
	return l1o.DocumentIds
}

func (l1o *Level1WorkflowRunOutput) GetLivePhotoIDs() []DocID {
	return l1o.LivePhotoIds
}

func (l1o *Level1WorkflowRunOutput) GetFirstName() string {
	if l1o.FirstName == constant.OnfidoNameNull {
		return constant.OnfidoNameNullReplace
	}
	return l1o.FirstName
}

func (l1o *Level1WorkflowRunOutput) GetLastName() string {
	if l1o.LastName == constant.OnfidoNameNull {
		return constant.OnfidoNameNullReplace
	}
	return l1o.LastName
}

func (l1o *Level1WorkflowRunOutput) GetDOB() string {
	return l1o.DateOfBirth
}

func (l1o *Level1WorkflowRunOutput) GetGender() dto.Gender {
	if l1o.Gender == "" {
		return dto.GenderUnknown
	}
	return dto.Gender(l1o.Gender)
}

func (l1o *Level1WorkflowRunOutput) GetCountry() string {
	return l1o.IssuingCountry
}

func (l1o *Level1WorkflowRunOutput) GetDocNumber() string {
	// 优先：如果有 document_number 就直接返回
	if l1o.DocumentNumber != "" {
		return l1o.DocumentNumber
	}
	// 次优：document_numbers 中获取 type = document_number 的 value 字段
	numMaps := l1o.GetDocNumbersMaps()
	if docNum, ok := numMaps["document_number"]; ok {
		return docNum
	}
	// 兜底：document_numbers 中获取 type = tc_kimlik 的 value 字段
	if docNum, ok := numMaps["tc_kimlik"]; ok {
		return docNum
	}
	return ""
}

func (l1o *Level1WorkflowRunOutput) GetDocNumbersMaps() map[string]string {
	docNumberMaps := make(map[string]string)
	for _, doc := range l1o.DocumentNumbers {
		docNumberMaps[doc.Type] = doc.Value
	}
	return docNumberMaps
}

func (l1o *Level1WorkflowRunOutput) GetNationality() string {
	return l1o.Nationality
}

func (l1o *Level1WorkflowRunOutput) GetPlaceOfBirth() string {
	return l1o.PlaceOfBirth
}

func (l1o *Level1WorkflowRunOutput) GetAddress() string {
	return l1o.Address
}

func (l1o *Level1WorkflowRunOutput) GetExpiryDate() string {
	return l1o.DateOfExpiry
}

func (l1o *Level1WorkflowRunOutput) GetIssuingDate() string {
	return l1o.IssuingDate
}

func (l1o *Level1WorkflowRunOutput) GetDocType() dto.DocType {
	return l1o.DocumentType.GetDocType()
}

func (l1o *Level1WorkflowRunOutput) GetRawDocType() string {
	return string(l1o.DocumentType)
}

func (l1o *Level1WorkflowRunOutput) GetSubDocType() enums.IDSubType {
	return l1o.DocumentType.GetSubDocType()
}

func (l1o *Level1WorkflowRunOutput) GetIdentifies() []*dto.Identify {
	r := make([]*dto.Identify, 0)
	identify := &dto.Identify{
		Type:       l1o.DocumentType.ToDocumentType(),
		Country:    l1o.GetCountry(),
		Firstname:  l1o.GetFirstName(),
		Lastname:   l1o.GetLastName(),
		Validuntil: l1o.GetExpiryDate(),
		Number:     l1o.GetDocNumber(),
		Dob:        l1o.GetDOB(),
		RawType:    string(l1o.DocumentType),
	}
	r = append(r, identify)

	return r
}

func (l1o *Level1WorkflowRunOutput) GetAddressParsed() AddressParsed {
	return AddressParsed{}
}

func (l1o *Level1WorkflowRunOutput) GetIDCard() string {
	return l1o.PersonalNumber
}

type AddressParsed struct {
	Country        string `json:"country"`
	Postcode       string `json:"postcode"`
	State          string `json:"state"`
	Town           string `json:"town"`
	IssuingCountry string `json:"issuing_country"`
}

// Level2WorkflowRunOutput Proof of Address workflow run output
type Level2WorkflowRunOutput struct {
	DocumentType       OnfidoDocumentType `json:"document_type"`
	Address            string             `json:"address"`
	AddressPostCode    string             `json:"address_post_code"`
	AddressState       string             `json:"address_state"`
	AddressTown        string             `json:"address_town"`
	AddressCountry     string             `json:"address_country"`
	FirstNames         string             `json:"first_names"`
	IssueDate          string             `json:"issue_date"`
	ExpiryDate         string             `json:"expiry_date"`
	Issuer             string             `json:"issuer"`
	LastNames          string             `json:"last_names"`
	SummaryPeriodEnd   string             `json:"summary_period_end"`
	SummaryPeriodStart string             `json:"summary_period_start"`
	PoaIds             []DocID            `json:"poa_ids"`
	AddressParsed      AddressParsed      `json:"address_parsed"`
	DocumentSourceType DocumentSourceType `json:"document_source_type"`
	IssuingCountry     string             `json:"issuing_country"`
}

func (l2o *Level2WorkflowRunOutput) GetDocIDs() []DocID {
	return l2o.PoaIds
}

func (l2o *Level2WorkflowRunOutput) GetLivePhotoIDs() []DocID {
	return []DocID{}
}

func (l2o *Level2WorkflowRunOutput) GetFirstName() string {
	if l2o.FirstNames == constant.OnfidoNameNull {
		return constant.OnfidoNameNullReplace
	}
	return l2o.FirstNames
}

func (l2o *Level2WorkflowRunOutput) GetLastName() string {
	if l2o.LastNames == constant.OnfidoNameNull {
		return constant.OnfidoNameNullReplace
	}
	return l2o.LastNames
}

func (l2o *Level2WorkflowRunOutput) GetDOB() string {
	return ""
}

func (l2o *Level2WorkflowRunOutput) GetGender() dto.Gender {
	return dto.GenderUnknown
}

// GetCountry returns issuing country
func (l2o *Level2WorkflowRunOutput) GetCountry() string {
	if l2o == nil {
		return ""
	}
	return l2o.IssuingCountry
}

func (l2o *Level2WorkflowRunOutput) GetDocNumber() string {
	return ""
}

func (l2o *Level2WorkflowRunOutput) GetNationality() string {
	return l2o.IssuingCountry
}

func (l2o *Level2WorkflowRunOutput) GetPlaceOfBirth() string {
	return ""
}

func (l2o *Level2WorkflowRunOutput) GetAddress() string {
	return l2o.Address
}

func (l2o *Level2WorkflowRunOutput) GetAddressCountry() string {
	if l2o == nil {
		return ""
	}
	return l2o.AddressCountry
}

func (l2o *Level2WorkflowRunOutput) GetAddressPostCode() string {
	if l2o == nil {
		return ""
	}
	return l2o.AddressPostCode
}

func (l2o *Level2WorkflowRunOutput) GetAddressState() string {
	if l2o == nil {
		return ""
	}
	return l2o.AddressState
}

func (l2o *Level2WorkflowRunOutput) GetAddressTown() string {
	if l2o == nil {
		return ""
	}
	return l2o.AddressTown
}

func (l2o *Level2WorkflowRunOutput) GetAddressParsed() AddressParsed {
	return AddressParsed{
		Country:  l2o.GetAddressCountry(),
		Postcode: l2o.GetAddressPostCode(),
		State:    l2o.GetAddressState(),
		Town:     l2o.GetAddressTown(),
	}
}

func (l2o *Level2WorkflowRunOutput) GetExpiryDate() string {
	if l2o == nil {
		return ""
	}
	if l2o.ExpiryDate != "" {
		return l2o.ExpiryDate
	}
	return l2o.SummaryPeriodEnd
}

func (l2o *Level2WorkflowRunOutput) GetIssuingDate() string {
	if l2o == nil {
		return ""
	}
	if l2o.IssueDate != "" {
		return l2o.IssueDate
	}
	return l2o.SummaryPeriodStart
}

func (l2o *Level2WorkflowRunOutput) GetDocType() dto.DocType {
	return l2o.DocumentType.GetDocType()
}

func (l2o *Level2WorkflowRunOutput) GetRawDocType() string {
	return string(l2o.DocumentType)
}

func (l2o *Level2WorkflowRunOutput) GetIdentifies() []*dto.Identify {
	return nil
}

func (l2o *Level2WorkflowRunOutput) GetIDCard() string {
	return ""
}

func (l2o *Level2WorkflowRunOutput) GetSubDocType() enums.IDSubType {
	return l2o.DocumentType.GetSubDocType()
}

type OnfidoWorkflowRunError struct {
	Type    string `json:"type"`
	Message string `json:"message"`
}

type OnfidoWorkflowRunLink struct {
	CompletedRedirectURL string `json:"completed_redirect_url"`
	ExpiredRedirectURL   string `json:"expired_redirect_url"`
	ExpiresAt            string `json:"expires_at"`
	Language             string `json:"language"`
	URL                  string `json:"url"`
}

type WorkflowRunTasks []WorkflowRunTask

type WorkflowRunTask struct {
	CreatedAt string    `json:"created_at"`
	ID        string    `json:"id"`
	TaskDefID TaskDefID `json:"task_def_id"`
	UpdatedAt string    `json:"updated_at"`
}

type SubCheckBreakdown struct {
	Properties interface{}  `json:"properties"`
	Result     ReportResult `json:"result"`
}

type WorkflowRunTaskDetail struct {
	CreatedAt string      `json:"created_at"`
	ID        string      `json:"id"`
	Input     interface{} `json:"input"`
	Output    interface{} `json:"output"`
	TaskDefID TaskDefID   `json:"task_def_id"`
	UpdatedAt string      `json:"updated_at"`
}

type Level2TaskOutput struct {
	Breakdown struct {
		DataComparison struct {
			Breakdown struct {
				Address   SubCheckBreakdown `json:"address"`
				FirstName SubCheckBreakdown `json:"first_name"`
				LastName  SubCheckBreakdown `json:"last_name"`
			} `json:"breakdown"`
			Result ReportResult `json:"result"`
		} `json:"data_comparison"`
		DocumentClassification struct {
			Breakdown struct {
				SupportedDocument SubCheckBreakdown `json:"supported_document"`
				ValidDocumentDate SubCheckBreakdown `json:"valid_document_date"`
			} `json:"breakdown"`
			Result ReportResult `json:"result"`
		} `json:"document_classification"`
		ImageIntegrity struct {
			Breakdown struct {
				ImageQuality SubCheckBreakdown `json:"image_quality"`
			} `json:"breakdown"`
			Result ReportResult `json:"result"`
		} `json:"image_integrity"`
	} `json:"breakdown"`
	Properties Level2WorkflowRunOutput `json:"properties"`
	Result     ReportResult            `json:"result"`
	Status     ReportStatus            `json:"status"`
	SubResult  ReportSubResult         `json:"sub_result"`
	UUID       string                  `json:"uuid"`
}

func (l2t *Level2TaskOutput) GetRejectReasons() []string {
	reasons := make([]string, 0)
	if l2t.Breakdown.DataComparison.Result.IsConsider() {
		reasons = append(reasons, RejectLabelDataComparison)
	}
	if l2t.Breakdown.DocumentClassification.Result.IsConsider() {
		reasons = append(reasons, RejectLabelDocumentClassification)
	}
	if l2t.Breakdown.ImageIntegrity.Result.IsConsider() {
		reasons = append(reasons, RejectLabelImageIntegrity)
	}

	return reasons
}

type Level1TaskOutput struct {
	Breakdown struct {
		AgeValidation struct {
			Breakdown struct {
				MinimumAcceptedAge SubCheckBreakdown `json:"minimum_accepted_age"`
			} `json:"breakdown"`
			Result ReportResult `json:"result"`
		} `json:"age_validation"`
		CompromisedDocument struct {
			Breakdown struct {
				DocumentDatabase SubCheckBreakdown `json:"document_database"`
				RepeatAttempts   SubCheckBreakdown `json:"repeat_attempts"`
			} `json:"breakdown"`
			Result ReportResult `json:"result"`
		} `json:"compromised_document"`
		DataComparison struct {
			Breakdown struct {
				DateOfBirth     SubCheckBreakdown `json:"date_of_birth"`
				DateOfExpiry    SubCheckBreakdown `json:"date_of_expiry"`
				DocumentNumbers SubCheckBreakdown `json:"document_numbers"`
				DocumentType    SubCheckBreakdown `json:"document_type"`
				FirstName       SubCheckBreakdown `json:"first_name"`
				Gender          SubCheckBreakdown `json:"gender"`
				IssuingCountry  SubCheckBreakdown `json:"issuing_country"`
				LastName        SubCheckBreakdown `json:"last_name"`
			} `json:"breakdown"`
			Result ReportResult `json:"result"`
		} `json:"data_comparison"`
		DataConsistency struct {
			Breakdown struct {
				DateOfBirth                SubCheckBreakdown `json:"date_of_birth"`
				DateOfExpiry               SubCheckBreakdown `json:"date_of_expiry"`
				DocumentNumbers            SubCheckBreakdown `json:"document_numbers"`
				DocumentType               SubCheckBreakdown `json:"document_type"`
				FirstName                  SubCheckBreakdown `json:"first_name"`
				Gender                     SubCheckBreakdown `json:"gender"`
				IssuingCountry             SubCheckBreakdown `json:"issuing_country"`
				LastName                   SubCheckBreakdown `json:"last_name"`
				MultipleDataSourcesPresent SubCheckBreakdown `json:"multiple_data_sources_present"`
				Nationality                SubCheckBreakdown `json:"nationality"`
			} `json:"breakdown"`
			Result ReportResult `json:"result"`
		} `json:"data_consistency"`
		DataValidation struct {
			Breakdown struct {
				DateOfBirth        SubCheckBreakdown `json:"date_of_birth"`
				DocumentExpiration SubCheckBreakdown `json:"document_expiration"`
				DocumentNumbers    SubCheckBreakdown `json:"document_numbers"`
				ExpiryDate         SubCheckBreakdown `json:"expiry_date"`
				Gender             SubCheckBreakdown `json:"gender"`
				Mrz                SubCheckBreakdown `json:"mrz"`
			} `json:"breakdown"`
			Result ReportResult `json:"result"`
		} `json:"data_validation"`
		ImageIntegrity struct {
			Breakdown struct {
				ColourPicture             SubCheckBreakdown `json:"colour_picture"`
				ConclusiveDocumentQuality SubCheckBreakdown `json:"conclusive_document_quality"`
				ImageQuality              SubCheckBreakdown `json:"image_quality"`
				SupportedDocument         SubCheckBreakdown `json:"supported_document"`
			} `json:"breakdown"`
			Result ReportResult `json:"result"`
		} `json:"image_integrity"`
		PoliceRecord struct {
			Breakdown struct {
				DocumentHasNotBeenRecordedAsLostStolenOrCompromised SubCheckBreakdown `json:"document_has_not_been_recorded_as_lost_stolen_or_compromised"`
			} `json:"breakdown"`
			Result ReportResult `json:"result"`
		} `json:"police_record"`
		VisualAuthenticity struct {
			Breakdown struct {
				DigitalTampering        SubCheckBreakdown `json:"digital_tampering"`
				FaceDetection           SubCheckBreakdown `json:"face_detection"`
				Fonts                   SubCheckBreakdown `json:"fonts"`
				OriginalDocumentPresent SubCheckBreakdown `json:"original_document_present"`
				Other                   SubCheckBreakdown `json:"other"`
				PictureFaceIntegrity    SubCheckBreakdown `json:"picture_face_integrity"`
				SecurityFeatures        SubCheckBreakdown `json:"security_features"`
				Template                SubCheckBreakdown `json:"template"`
			} `json:"breakdown"`
			Result ReportResult `json:"result"`
		} `json:"visual_authenticity"`
	} `json:"breakdown"`
	Properties struct {
		DateOfBirth     string             `json:"date_of_birth"`
		DateOfExpiry    string             `json:"date_of_expiry"`
		DocumentNumber  string             `json:"document_number"`
		DocumentNumbers []Document         `json:"document_numbers"`
		DocumentType    OnfidoDocumentType `json:"document_type"`
		FirstName       string             `json:"first_name"`
		IssuingCountry  string             `json:"issuing_country"`
		LastName        string             `json:"last_name"`
	} `json:"properties"`
	Result    ReportResult    `json:"result"`
	Status    ReportStatus    `json:"status"`
	SubResult ReportSubResult `json:"sub_result"`
	UUID      string          `json:"uuid"`
}

func (l1t *Level1TaskOutput) GetRejectReasons() []string {
	reasons := make([]string, 0)
	if l1t.Breakdown.AgeValidation.Result.IsConsider() {
		reasons = append(reasons, RejectLabelAgeValidation)
	}
	if l1t.Breakdown.CompromisedDocument.Result.IsConsider() {
		reasons = append(reasons, RejectLabelCompromisedDocument)
	}
	if l1t.Breakdown.DataComparison.Result.IsConsider() {
		reasons = append(reasons, RejectLabelDataComparison)
	}
	if l1t.Breakdown.DataConsistency.Result.IsConsider() {
		reasons = append(reasons, RejectLabelDataConsistency)
	}
	if l1t.Breakdown.DataValidation.Result.IsConsider() {
		reasons = append(reasons, RejectLabelDataValidation)
	}
	if l1t.Breakdown.ImageIntegrity.Result.IsConsider() {
		reasons = append(reasons, RejectLabelImageIntegrity)
	}
	if l1t.Breakdown.PoliceRecord.Result.IsConsider() {
		reasons = append(reasons, RejectLabelPoliceRecord)
	}
	if l1t.Breakdown.VisualAuthenticity.Result.IsConsider() {
		reasons = append(reasons, RejectLabelVisualAuthenticity)
	}

	return reasons
}

type UpdateApplicantAddress struct {
	Address struct {
		FlatNumber     string `json:"flat_number"`
		BuildingName   string `json:"building_name"`
		BuildingNumber string `json:"building_number"`
		Street         string `json:"street"`
		SubStreet      string `json:"sub_street"`
		City           string `json:"city"`
		Town           string `json:"town"`
		Postcode       string `json:"postcode"`
		Country        string `json:"country"`
	} `json:"address"`
}

type DocumentInfo struct {
	ApplicantID    string             `json:"applicant_id"`
	ID             string             `json:"id"`
	FileName       string             `json:"file_name"`
	FileType       string             `json:"file_type"`
	FileSize       int64              `json:"file_size"`
	Type           OnfidoDocumentType `json:"type"`
	Side           string             `json:"side"`
	IssuingCountry string             `json:"issuing_country"`
	SdkWarnings    interface{}        `json:"sdk_warnings"`
	CreatedAt      string             `json:"created_at"`
	Href           string             `json:"href"`
	DownloadHref   string             `json:"download_href"`
}

type LivePhotoInfo struct {
	ID           string `json:"id"`
	CreatedAt    string `json:"created_at"`
	FileName     string `json:"file_name"`
	FileType     string `json:"file_type"`
	FileSize     int64  `json:"file_size"`
	Href         string `json:"href"`
	DownloadHref string `json:"download_href"`
}

func GetDefaultApplicantAddress() *UpdateApplicantAddress {
	return &UpdateApplicantAddress{
		Address: struct {
			FlatNumber     string `json:"flat_number"`
			BuildingName   string `json:"building_name"`
			BuildingNumber string `json:"building_number"`
			Street         string `json:"street"`
			SubStreet      string `json:"sub_street"`
			City           string `json:"city"`
			Town           string `json:"town"`
			Postcode       string `json:"postcode"`
			Country        string `json:"country"`
		}{
			FlatNumber:     "Brooklands",
			BuildingName:   "",
			BuildingNumber: "8",
			Street:         "Courageous Way",
			SubStreet:      "",
			City:           "",
			Town:           "Milton Keynes",
			Postcode:       "MK10 7GJ",
			Country:        "GBR",
		},
	}
}

const (
	ErrInvalidApplicant = errors.Sentinel("invalid applicant")
)

func ensureWorkflowOutput(i interface{}) (WorkflowOutput, error) {
	if a, ok := i.(WorkflowOutput); ok {
		return a, nil
	}

	return nil, ErrInvalidApplicant
}

func OnfidoWorkflowOutputCov(output interface{}, level dto.KYCLevel) (WorkflowOutput, error) {
	var (
		wfo                  WorkflowOutput
		errLv1Cnv, errLv2Cnv error
	)
	out, _ := json.Marshal(output)
	if level == dto.Level1 || level == dto.Level1Secondary {
		lv1Out := &Level1WorkflowRunOutput{}
		opLv1Err := json.Unmarshal(out, lv1Out)
		if opLv1Err != nil {
			return nil, opLv1Err
		}
		wfo, errLv1Cnv = ensureWorkflowOutput(lv1Out)
		if errLv1Cnv != nil {
			return nil, errLv1Cnv
		}
	} else {
		lv2Out := &Level2WorkflowRunOutput{}
		opLv2Err := json.Unmarshal(out, lv2Out)
		if opLv2Err != nil {
			return nil, opLv2Err
		}
		wfo, errLv2Cnv = ensureWorkflowOutput(lv2Out)
		if errLv2Cnv != nil {
			return nil, errLv2Cnv
		}
	}
	return wfo, nil
}

// ListDocuments https://documentation.onfido.com/#list-documents
type ListDocuments struct {
	Documents []*DocumentInfo `json:"documents"`
}

// ListLivePhotos https://documentation.onfido.com/#list-live-photos
type ListLivePhotos struct {
	LivePhotos []*LivePhotoInfo `json:"live_photos"`
}
